package com.gitee.wsl.android.ext.store

//package com.dylanc.longan

import android.content.ContentResolver
import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.media.MediaScannerConnection
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import androidx.annotation.RequiresApi
import androidx.annotation.RequiresPermission
import androidx.core.content.contentValuesOf
import com.gitee.wsl.android.ext.ApplicationInit.application
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.suspendCancellableCoroutine
import java.io.File

object ContentResolverExt {

}

inline val contentResolver: ContentResolver get() = application.contentResolver

inline val EXTERNAL_MEDIA_IMAGES_URI: Uri
    get() = MediaStore.Images.Media.EXTERNAL_CONTENT_URI

inline val EXTERNAL_MEDIA_VIDEO_URI: Uri
    get() = MediaStore.Video.Media.EXTERNAL_CONTENT_URI

inline val EXTERNAL_MEDIA_AUDIO_URI: Uri
    get() = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI

@get:RequiresApi(Build.VERSION_CODES.Q)
inline val EXTERNAL_MEDIA_DOWNLOADS_URI: Uri
    get() = MediaStore.Downloads.EXTERNAL_CONTENT_URI

@OptIn(ExperimentalCoroutinesApi::class)
suspend fun ContentResolver.scanMediaStoreUri(uri: Uri, mimeType: String, context:Context = application): Uri? {
    val cursor = query(
        uri,
        arrayOf(MediaStore.Files.FileColumns.DATA),
        null,
        null,
        null
    ) ?: throw Exception("Uri $uri could not be found")

    val path = cursor.use {
        if (!cursor.moveToFirst()) {
            throw Exception("Uri $uri could not be found")
        }

        cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATA))
    }

    return suspendCancellableCoroutine { continuation ->
        MediaScannerConnection.scanFile(
            context,
            arrayOf(path),
            arrayOf(mimeType)
        ) { _, scannedUri ->
            if (scannedUri == null) {
                continuation.cancel(Exception("File $path could not be scanned"))
            } else {
                continuation.resume(scannedUri,null)
            }
        }
    }
}

@OptIn(ExperimentalCoroutinesApi::class)
suspend fun ContentResolver.scanMediaStoreFile(file: File, mimeType: String, context:Context = application): Uri? {
    return suspendCancellableCoroutine { continuation ->
        MediaScannerConnection.scanFile(
            context,
            arrayOf(file.toString()),
            arrayOf(mimeType)
        ) { _, scannedUri ->
            if (scannedUri == null) {
                continuation.cancel(Exception("File $file could not be scanned"))
            } else {
                continuation.resume(scannedUri,null)
            }
        }
    }
}

fun ContentResolver.createMediaStoreUri(
    filename: String,
    collection: Uri = MediaStore.Files.getContentUri("external"),
    directory: String?
): Uri? {
    val newEntry = ContentValues().apply {
        put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
        if (directory !== null) put(MediaStore.MediaColumns.DATA, "$directory/$filename")
    }

    return insert(collection, newEntry)
}



inline fun <R> ContentResolver.query(
    uri: Uri,
    projection: Array<String>? = null,
    selection: String? = null,
    selectionArgs: Array<String>? = null,
    sortOrder: String? = null,
    block: (Cursor) -> R
): R? =
    query(uri, projection, selection, selectionArgs, sortOrder)?.use(block)

inline fun <R> ContentResolver.queryFirst(
    uri: Uri,
    projection: Array<String>? = null,
    selection: String? = null,
    selectionArgs: Array<String>? = null,
    sortOrder: String? = null,
    block: (Cursor) -> R
): R? =
    query(uri, projection, selection, selectionArgs, sortOrder) {
        if (it.moveToFirst()) block(it) else null
    }

inline fun <R> ContentResolver.queryLast(
    uri: Uri,
    projection: Array<String>? = null,
    selection: String? = null,
    selectionArgs: Array<String>? = null,
    sortOrder: String? = null,
    block: (Cursor) -> R
): R? =
    query(uri, projection, selection, selectionArgs, sortOrder) {
        if (it.moveToLast()) block(it) else null
    }

inline fun <R> ContentResolver.queryMediaImages(
    projection: Array<String>? = null,
    selection: String? = null,
    selectionArgs: Array<String>? = null,
    sortOrder: String? = null,
    block: (Cursor) -> R
): R? =
    query(EXTERNAL_MEDIA_IMAGES_URI, projection, selection, selectionArgs, sortOrder, block)

inline fun <R> ContentResolver.queryMediaVideos(
    projection: Array<String>? = null,
    selection: String? = null,
    selectionArgs: Array<String>? = null,
    sortOrder: String? = null,
    block: (Cursor) -> R
): R? =
    query(EXTERNAL_MEDIA_VIDEO_URI, projection, selection, selectionArgs, sortOrder, block)

inline fun <R> ContentResolver.queryMediaAudios(
    projection: Array<String>? = null,
    selection: String? = null,
    selectionArgs: Array<String>? = null,
    sortOrder: String? = null,
    block: (Cursor) -> R
): R? =
    query(EXTERNAL_MEDIA_AUDIO_URI, projection, selection, selectionArgs, sortOrder, block)

@RequiresApi(Build.VERSION_CODES.Q)
inline fun <R> ContentResolver.queryMediaDownloads(
    projection: Array<String>? = null,
    selection: String? = null,
    selectionArgs: Array<String>? = null,
    sortOrder: String? = null,
    block: (Cursor) -> R
): R? =
    query(EXTERNAL_MEDIA_DOWNLOADS_URI, projection, selection, selectionArgs, sortOrder, block)

fun ContentResolver.insert(uri: Uri, vararg pairs: Pair<String, Any?>): Uri? =
    contentResolver.insert(uri, contentValuesOf(*pairs))

fun ContentResolver.insertMediaImage(vararg pairs: Pair<String, Any?>): Uri? =
    contentResolver.insert(EXTERNAL_MEDIA_IMAGES_URI, *pairs)

fun ContentResolver.insertMediaVideo(vararg pairs: Pair<String, Any?>): Uri? =
    contentResolver.insert(EXTERNAL_MEDIA_VIDEO_URI, *pairs)

fun ContentResolver.insertMediaAudio(vararg pairs: Pair<String, Any?>): Uri? =
    contentResolver.insert(EXTERNAL_MEDIA_AUDIO_URI, *pairs)

@RequiresApi(Build.VERSION_CODES.Q)
fun ContentResolver.insertMediaDownload(vararg pairs: Pair<String, Any?>): Uri? =
    contentResolver.insert(EXTERNAL_MEDIA_DOWNLOADS_URI, *pairs)

fun ContentResolver.update(
    @RequiresPermission.Write uri: Uri,
    vararg pairs: Pair<String, Any?>,
    where: String? = null,
    selectionArgs: Array<String>? = null
): Int =
    update(uri, contentValuesOf(*pairs), where, selectionArgs)

@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
fun ContentResolver.delete(
    @RequiresPermission.Write uri: Uri,
    where: String? = null,
    selectionArgs: Array<String>? = null
): Int =
    delete(uri, where, selectionArgs)

fun ContentResolver.count(
    uri: Uri,
    selection: String? = null,
    selectionArgs: Array<String>? = null
): Int {
    var result = 0
    query(
        uri, arrayOf("count(*) AS count"),
        selection,
        selectionArgs,
        null
    )?.run {
        moveToFirst()
        if (count > 0) {
            result = getInt(0)
        }
        close()
    }
    return result
}

fun ContentResolver.contentCount(
    uri: Uri, projection: Array<String> = arrayOf("_id"), selection: String? = null, selectionArgs: Array<String>? = null
): Int {
    var result = 0
    query(
        uri, projection,
        selection,
        selectionArgs,
        null
    )?.run {
        result = count
    }
    return result
}